/* reading from the same location to different destination locations
 */


#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>
#include <omp.h>

#include "defines.h"
#include "papi_test.h"

long *src;
long result;
unsigned long size;

void pranith_start() {printf("starting...\n");}
void pranith_stop() {printf("stopping...\n");}
void recordTime(struct timeval* current)
{
    gettimeofday(current, NULL);

    return;
}

float diffTime(struct timeval before, struct timeval after)
{
    float time_sec = ((after.tv_sec - before.tv_sec) + ((after.tv_usec - before.tv_usec) / 1000000.0));

    return time_sec;
}

void warmup()
{
  unsigned long j;
  size = 256 * 1024 * 1024 / sizeof(long); // 256 MB
  src = (long *)malloc(sizeof(long) * size);
  //initialize array
  for (j = 0; j < size; j++)
    src[j] = 8;
}

const int eventlist[] = {
    PAPI_TOT_INS,
    PAPI_L1_DCA,
    PAPI_L1_TCM,
    PAPI_L2_DCA,
    PAPI_L2_TCM,
    PAPI_L3_DCA,
    PAPI_L3_TCM,
    0
};

void Thread(num_iter)
{
  unsigned int j, i = 0, k;
  volatile long dest;
  int retval;
  int EventSet = PAPI_NULL;
  long long values = 0;
  double final = 0;
  PAPI_event_info_t evinfo;
  char event_name[PAPI_MAX_STR_LEN];

  int tid = omp_get_thread_num();
  if ( ( retval = PAPI_create_eventset( &EventSet ) ) != PAPI_OK )
    test_fail( __FILE__, __LINE__, "PAPI_create_eventset", retval );
  for (j = 0; eventlist[j] != 0; j++)
  {
    retval = PAPI_event_code_to_name( eventlist[j], event_name );

    if ( retval != PAPI_OK )
      test_fail( __FILE__, __LINE__, "PAPI_event_code_to_name", retval );

    if ( (retval = PAPI_add_event( EventSet, eventlist[j] ) ) != PAPI_OK )
      continue;

    if ( (retval = PAPI_get_event_info( eventlist[j], &evinfo )) != PAPI_OK )
      test_fail( __FILE__, __LINE__, "PAPI_get_event_info", retval );

    if (tid == 0)
        printf( "\nEvent: %s\nShort: %s\nLong: %s\n\n",
                evinfo.symbol, evinfo.short_descr, evinfo.long_descr );

    PAPI_start(EventSet);
    if ( ( retval = PAPI_reset( EventSet ) ) != PAPI_OK )
      test_fail( __FILE__, __LINE__, "PAPI_reset", retval );

    for(k = 0; k < num_iter; k++)
    {
      dest = src[i + indexarr0];
      dest = src[i + indexarr1];
      dest = src[i + indexarr2];
      dest = src[i + indexarr3];
      dest = src[i + indexarr4];
      dest = src[i + indexarr5];
      dest = src[i + indexarr6];
      dest = src[i + indexarr7];
      dest = src[i + indexarr8];
      dest = src[i + indexarr9];
      dest = src[i + indexarr10];
      dest = src[i + indexarr11];
      dest = src[i + indexarr12];
      dest = src[i + indexarr13];
      dest = src[i + indexarr14];
      dest = src[i + indexarr15];
      dest = src[i + indexarr16];
      dest = src[i + indexarr17];
      dest = src[i + indexarr18];
      dest = src[i + indexarr19];
      dest = src[i + indexarr20];
      dest = src[i + indexarr21];
      dest = src[i + indexarr22];
      dest = src[i + indexarr23];
      dest = src[i + indexarr24];
      dest = src[i + indexarr25];
      dest = src[i + indexarr26];
      dest = src[i + indexarr27];
      dest = src[i + indexarr28];
      dest = src[i + indexarr29];
      dest = src[i + indexarr30];
      dest = src[i + indexarr31];
      dest = src[i + indexarr32];
      dest = src[i + indexarr33];
      dest = src[i + indexarr34];
      dest = src[i + indexarr35];
      dest = src[i + indexarr36];
      dest = src[i + indexarr37];
      dest = src[i + indexarr38];
      dest = src[i + indexarr39];
      dest = src[i + indexarr40];
      dest = src[i + indexarr41];
      dest = src[i + indexarr42];
      dest = src[i + indexarr43];
      dest = src[i + indexarr44];
      dest = src[i + indexarr45];
      dest = src[i + indexarr46];
      dest = src[i + indexarr47];
      dest = src[i + indexarr48];
      dest = src[i + indexarr49];
      dest = src[i + indexarr50];
      dest = src[i + indexarr51];
      dest = src[i + indexarr52];
      dest = src[i + indexarr53];
      dest = src[i + indexarr54];
      dest = src[i + indexarr55];
      dest = src[i + indexarr56];
      dest = src[i + indexarr57];
      dest = src[i + indexarr58];
      dest = src[i + indexarr59];
      dest = src[i + indexarr60];
      dest = src[i + indexarr61];
      dest = src[i + indexarr62];
      dest = src[i + indexarr63];
      dest = src[i + indexarr64];
      dest = src[i + indexarr65];
      dest = src[i + indexarr66];
      dest = src[i + indexarr67];
      dest = src[i + indexarr68];
      dest = src[i + indexarr69];
      dest = src[i + indexarr70];
      dest = src[i + indexarr71];
      dest = src[i + indexarr72];
      dest = src[i + indexarr73];
      dest = src[i + indexarr74];
      dest = src[i + indexarr75];
      dest = src[i + indexarr76];
      dest = src[i + indexarr77];
      dest = src[i + indexarr78];
      dest = src[i + indexarr79];
      dest = src[i + indexarr80];
      dest = src[i + indexarr81];
      dest = src[i + indexarr82];
      dest = src[i + indexarr83];
      dest = src[i + indexarr84];
      dest = src[i + indexarr85];
      dest = src[i + indexarr86];
      dest = src[i + indexarr87];
      dest = src[i + indexarr88];
      dest = src[i + indexarr89];
      dest = src[i + indexarr90];
      dest = src[i + indexarr91];
      dest = src[i + indexarr92];
      dest = src[i + indexarr93];
      dest = src[i + indexarr94];
      dest = src[i + indexarr95];
      dest = src[i + indexarr96];
      dest = src[i + indexarr97];
      dest = src[i + indexarr98];
      dest = src[i + indexarr99];
      dest = src[i + indexarr100];
      dest = src[i + indexarr101];
      dest = src[i + indexarr102];
      dest = src[i + indexarr103];
      dest = src[i + indexarr104];
      dest = src[i + indexarr105];
      dest = src[i + indexarr106];
      dest = src[i + indexarr107];
      dest = src[i + indexarr108];
      dest = src[i + indexarr109];
      dest = src[i + indexarr110];
      dest = src[i + indexarr111];
      dest = src[i + indexarr112];
      dest = src[i + indexarr113];
      dest = src[i + indexarr114];
      dest = src[i + indexarr115];
      dest = src[i + indexarr116];
      dest = src[i + indexarr117];
      dest = src[i + indexarr118];
      dest = src[i + indexarr119];
      dest = src[i + indexarr120];
      dest = src[i + indexarr121];
      dest = src[i + indexarr122];
      dest = src[i + indexarr123];
      dest = src[i + indexarr124];
      dest = src[i + indexarr125];
      dest = src[i + indexarr126];
      dest = src[i + indexarr127];
      dest = src[i + indexarr128];
      dest = src[i + indexarr129];
      dest = src[i + indexarr130];
      dest = src[i + indexarr131];
      dest = src[i + indexarr132];
      dest = src[i + indexarr133];
      dest = src[i + indexarr134];
      dest = src[i + indexarr135];
      dest = src[i + indexarr136];
      dest = src[i + indexarr137];
      dest = src[i + indexarr138];
      dest = src[i + indexarr139];
      dest = src[i + indexarr140];
      dest = src[i + indexarr141];
      dest = src[i + indexarr142];
      dest = src[i + indexarr143];
      dest = src[i + indexarr144];
      dest = src[i + indexarr145];
      dest = src[i + indexarr146];
      dest = src[i + indexarr147];
      dest = src[i + indexarr148];
      dest = src[i + indexarr149];
      dest = src[i + indexarr150];
      dest = src[i + indexarr151];
      dest = src[i + indexarr152];
      dest = src[i + indexarr153];
      dest = src[i + indexarr154];
      dest = src[i + indexarr155];
      dest = src[i + indexarr156];
      dest = src[i + indexarr157];
      dest = src[i + indexarr158];
      dest = src[i + indexarr159];
      dest = src[i + indexarr160];
      dest = src[i + indexarr161];
      dest = src[i + indexarr162];
      dest = src[i + indexarr163];
      dest = src[i + indexarr164];
      dest = src[i + indexarr165];
      dest = src[i + indexarr166];
      dest = src[i + indexarr167];
      dest = src[i + indexarr168];
      dest = src[i + indexarr169];
      dest = src[i + indexarr170];
      dest = src[i + indexarr171];
      dest = src[i + indexarr172];
      dest = src[i + indexarr173];
      dest = src[i + indexarr174];
      dest = src[i + indexarr175];
      dest = src[i + indexarr176];
      dest = src[i + indexarr177];
      dest = src[i + indexarr178];
      dest = src[i + indexarr179];
      dest = src[i + indexarr180];
      dest = src[i + indexarr181];
      dest = src[i + indexarr182];
      dest = src[i + indexarr183];
      dest = src[i + indexarr184];
      dest = src[i + indexarr185];
      dest = src[i + indexarr186];
      dest = src[i + indexarr187];
      dest = src[i + indexarr188];
      dest = src[i + indexarr189];
      dest = src[i + indexarr190];
      dest = src[i + indexarr191];
      dest = src[i + indexarr192];
      dest = src[i + indexarr193];
      dest = src[i + indexarr194];
      dest = src[i + indexarr195];
      dest = src[i + indexarr196];
      dest = src[i + indexarr197];
      dest = src[i + indexarr198];
      dest = src[i + indexarr199];
      dest = src[i + indexarr200];
      dest = src[i + indexarr201];
      dest = src[i + indexarr202];
      dest = src[i + indexarr203];
      dest = src[i + indexarr204];
      dest = src[i + indexarr205];
      dest = src[i + indexarr206];
      dest = src[i + indexarr207];
      dest = src[i + indexarr208];
      dest = src[i + indexarr209];
      dest = src[i + indexarr210];
      dest = src[i + indexarr211];
      dest = src[i + indexarr212];
      dest = src[i + indexarr213];
      dest = src[i + indexarr214];
      dest = src[i + indexarr215];
      dest = src[i + indexarr216];
      dest = src[i + indexarr217];
      dest = src[i + indexarr218];
      dest = src[i + indexarr219];
      dest = src[i + indexarr220];
      dest = src[i + indexarr221];
      dest = src[i + indexarr222];
      dest = src[i + indexarr223];
      dest = src[i + indexarr224];
      dest = src[i + indexarr225];
      dest = src[i + indexarr226];
      dest = src[i + indexarr227];
      dest = src[i + indexarr228];
      dest = src[i + indexarr229];
      dest = src[i + indexarr230];
      dest = src[i + indexarr231];
      dest = src[i + indexarr232];
      dest = src[i + indexarr233];
      dest = src[i + indexarr234];
      dest = src[i + indexarr235];
      dest = src[i + indexarr236];
      dest = src[i + indexarr237];
      dest = src[i + indexarr238];
      dest = src[i + indexarr239];
      dest = src[i + indexarr240];
      dest = src[i + indexarr241];
      dest = src[i + indexarr242];
      dest = src[i + indexarr243];
      dest = src[i + indexarr244];
      dest = src[i + indexarr245];
      dest = src[i + indexarr246];
      dest = src[i + indexarr247];
      dest = src[i + indexarr248];
      dest = src[i + indexarr249];
      dest = src[i + indexarr250];
      dest = src[i + indexarr251];
      dest = src[i + indexarr252];
      dest = src[i + indexarr253];
      dest = src[i + indexarr254];
      dest = src[i + indexarr255];
      dest = src[i + indexarr256];
      dest = src[i + indexarr257];
      dest = src[i + indexarr258];
      dest = src[i + indexarr259];
      dest = src[i + indexarr260];
      dest = src[i + indexarr261];
      dest = src[i + indexarr262];
      dest = src[i + indexarr263];
      dest = src[i + indexarr264];
      dest = src[i + indexarr265];
      dest = src[i + indexarr266];
      dest = src[i + indexarr267];
      dest = src[i + indexarr268];
      dest = src[i + indexarr269];
      dest = src[i + indexarr270];
      dest = src[i + indexarr271];
      dest = src[i + indexarr272];
      dest = src[i + indexarr273];
      dest = src[i + indexarr274];
      dest = src[i + indexarr275];
      dest = src[i + indexarr276];
      dest = src[i + indexarr277];
      dest = src[i + indexarr278];
      dest = src[i + indexarr279];
      dest = src[i + indexarr280];
      dest = src[i + indexarr281];
      dest = src[i + indexarr282];
      dest = src[i + indexarr283];
      dest = src[i + indexarr284];
      dest = src[i + indexarr285];
      dest = src[i + indexarr286];
      dest = src[i + indexarr287];
      dest = src[i + indexarr288];
      dest = src[i + indexarr289];
      dest = src[i + indexarr290];
      dest = src[i + indexarr291];
      dest = src[i + indexarr292];
      dest = src[i + indexarr293];
      dest = src[i + indexarr294];
      dest = src[i + indexarr295];
      dest = src[i + indexarr296];
      dest = src[i + indexarr297];
      dest = src[i + indexarr298];
      dest = src[i + indexarr299];
      dest = src[i + indexarr300];
      dest = src[i + indexarr301];
      dest = src[i + indexarr302];
      dest = src[i + indexarr303];
      dest = src[i + indexarr304];
      dest = src[i + indexarr305];
      dest = src[i + indexarr306];
      dest = src[i + indexarr307];
      dest = src[i + indexarr308];
      dest = src[i + indexarr309];
      dest = src[i + indexarr310];
      dest = src[i + indexarr311];
      dest = src[i + indexarr312];
      dest = src[i + indexarr313];
      dest = src[i + indexarr314];
      dest = src[i + indexarr315];
      dest = src[i + indexarr316];
      dest = src[i + indexarr317];
      dest = src[i + indexarr318];
      dest = src[i + indexarr319];
      dest = src[i + indexarr320];
      dest = src[i + indexarr321];
      dest = src[i + indexarr322];
      dest = src[i + indexarr323];
      dest = src[i + indexarr324];
      dest = src[i + indexarr325];
      dest = src[i + indexarr326];
      dest = src[i + indexarr327];
      dest = src[i + indexarr328];
      dest = src[i + indexarr329];
      dest = src[i + indexarr330];
      dest = src[i + indexarr331];
      dest = src[i + indexarr332];
      dest = src[i + indexarr333];
      dest = src[i + indexarr334];
      dest = src[i + indexarr335];
      dest = src[i + indexarr336];
      dest = src[i + indexarr337];
      dest = src[i + indexarr338];
      dest = src[i + indexarr339];
      dest = src[i + indexarr340];
      dest = src[i + indexarr341];
      dest = src[i + indexarr342];
      dest = src[i + indexarr343];
      dest = src[i + indexarr344];
      dest = src[i + indexarr345];
      dest = src[i + indexarr346];
      dest = src[i + indexarr347];
      dest = src[i + indexarr348];
      dest = src[i + indexarr349];
      dest = src[i + indexarr350];
      dest = src[i + indexarr351];
      dest = src[i + indexarr352];
      dest = src[i + indexarr353];
      dest = src[i + indexarr354];
      dest = src[i + indexarr355];
      dest = src[i + indexarr356];
      dest = src[i + indexarr357];
      dest = src[i + indexarr358];
      dest = src[i + indexarr359];
      dest = src[i + indexarr360];
      dest = src[i + indexarr361];
      dest = src[i + indexarr362];
      dest = src[i + indexarr363];
      dest = src[i + indexarr364];
      dest = src[i + indexarr365];
      dest = src[i + indexarr366];
      dest = src[i + indexarr367];
      dest = src[i + indexarr368];
      dest = src[i + indexarr369];
      dest = src[i + indexarr370];
      dest = src[i + indexarr371];
      dest = src[i + indexarr372];
      dest = src[i + indexarr373];
      dest = src[i + indexarr374];
      dest = src[i + indexarr375];
      dest = src[i + indexarr376];
      dest = src[i + indexarr377];
      dest = src[i + indexarr378];
      dest = src[i + indexarr379];
      dest = src[i + indexarr380];
      dest = src[i + indexarr381];
      dest = src[i + indexarr382];
      dest = src[i + indexarr383];
      dest = src[i + indexarr384];
      dest = src[i + indexarr385];
      dest = src[i + indexarr386];
      dest = src[i + indexarr387];
      dest = src[i + indexarr388];
      dest = src[i + indexarr389];
      dest = src[i + indexarr390];
      dest = src[i + indexarr391];
      dest = src[i + indexarr392];
      dest = src[i + indexarr393];
      dest = src[i + indexarr394];
      dest = src[i + indexarr395];
      dest = src[i + indexarr396];
      dest = src[i + indexarr397];
      dest = src[i + indexarr398];
      dest = src[i + indexarr399];

      /* make subsequent iterations dependent on previous iterations */
      i += indexarr399;

      if (i+indexarr399 >= size)
        i = 0;
    }

    if ( ( retval = PAPI_read( EventSet, &values ) ) != PAPI_OK )
      test_fail( __FILE__, __LINE__, "PAPI_read", retval );

    PAPI_stop(EventSet, NULL);
    if ( ( retval =
          PAPI_remove_event( EventSet, eventlist[j] ) ) != PAPI_OK )
      test_fail( __FILE__, __LINE__, "PAPI_remove_event", retval );

    double res = values;
    printf("\nThread tid : %d, %s, %e", omp_get_thread_num(), event_name, res);
  }

  result = final;

  PAPI_unregister_thread();
  return;
}

int main(int argc, char* argv[])
{
  warmup();
  pranith_start();
  int num_mem_ops = 400, i = 0;
  int retval;

  unsigned long num_iter = 5000000000 / num_mem_ops;
  struct timeval before, after;

  int num_threads = omp_get_max_threads();

  retval = PAPI_library_init(PAPI_VER_CURRENT);
  if ( retval != PAPI_VER_CURRENT )
    test_fail( __FILE__, __LINE__, "PAPI_library_init", retval );

  retval =
    PAPI_thread_init( ( unsigned
          long ( * )( void ) ) ( omp_get_thread_num ) );
  if ( retval != PAPI_OK ) {
    if ( retval == PAPI_ESBSTR )
      test_skip( __FILE__, __LINE__, "PAPI_thread_init", retval );
    else
      test_fail( __FILE__, __LINE__, "PAPI_thread_init", retval );
  }

  recordTime(&before);
#pragma omp parallel for schedule(static)
  for (i = 0; i < num_threads; i++)
    Thread(num_iter/num_threads);
  recordTime(&after);

  printf("time taken %f\n", diffTime(before, after));
  printf("num iter %d M\n", (int) (num_iter / 1000000));
  pranith_stop();

  fflush(NULL);
  return 0;
}
